package data

import (
	"fmt"
	"geekbang-go-homework/week04/internal/data/ent"

	"github.com/pkg/errors"

	"golang.org/x/net/context"
)

// WithTx 通用事务执行方法
func WithTx(ctx context.Context, client *ent.Client, tx *ent.Tx, fn func(tx *ent.Tx) error) (err error) {
	if tx != nil {
		return fn(tx)
	}
	tx, err = client.Tx(ctx)
	if err != nil {
		return err
	}
	defer func() {
		if v := recover(); v != nil {
			if rerr := tx.Rollback(); rerr != nil {
				err = errors.New(fmt.Sprintf("recover: %s rollback error: %s", v, rerr))
			} else {
				err = errors.New(fmt.Sprint(v))
			}
		}
	}()
	if err = fn(tx); err != nil {
		if rerr := tx.Rollback(); rerr != nil {
			err = errors.Wrapf(err, "rolling back transaction: %v", rerr)
		}
		return err
	}
	if err := tx.Commit(); err != nil {
		return errors.Wrapf(err, "committing transaction: %v", err)
	}
	return nil
}
